package com.d3works.apps.purchase.service;

import com.d3works.apps.account.db.TaxLine;
import com.d3works.apps.base.db.Product;
import com.d3works.apps.base.service.tax.TaxService;
import com.d3works.apps.base.utils.Lambda;
import com.d3works.apps.purchase.db.PurchaseOrder;
import com.d3works.apps.purchase.db.PurchaseOrderLine;
import com.d3works.apps.tool.reader.ExcelReaderService;
import com.d3works.db.Query;
import com.d3works.inject.Beans;
import com.d3works.meta.db.MetaFile;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PurchaseOrderLineImportService extends ExcelReaderService {

  public static final int HEADER_SIZE = 8;

  final Logger logger = LoggerFactory.getLogger(getClass());

  public PurchaseOrderLineImportService(MetaFile metaFile) {}

  public List<PurchaseOrderLine> readAllLines(PurchaseOrder parentOrder) throws Exception {
    String[] sheetNames = getSheetNames();
    if (sheetNames.length == 0) {
      return new ArrayList<>();
    }
    String sheetName = sheetNames[0];
    String[] datas = null;
    List<String[]> rowList = new ArrayList<>();
    int index = 0;
    while ((datas = read(sheetName, index, HEADER_SIZE)) != null) {
      rowList.add(datas);
      index++;
    }
    return convertToOrderLines(parentOrder, rowList);
  }

  private List<PurchaseOrderLine> convertToOrderLines(
      PurchaseOrder parentOrder, List<String[]> rowList) throws Exception {
    int i = 2;
    int len = rowList.size();
    PurchaseOrderLineService lineService = Beans.get(PurchaseOrderLineService.class);
    List<PurchaseOrderLine> orderLines = new ArrayList<>();

    List<TaxLine> taxLines = new ArrayList<>();

    for (; i < len; i++) {
      String[] rows = rowList.get(i);
      PurchaseOrderLine line = new PurchaseOrderLine();
      line.setProductCode(rows[0]);
      line.setProductName(rows[1]);
      line.setQty(new BigDecimal(rows[3]));
      line.setInTaxPrice((new BigDecimal(rows[5])));
      taxLines.add(getTaxLine(rows[7]));
      orderLines.add(line);
    }
    orderLines = appendProductInfo(orderLines);

    int idx = -1;
    for (PurchaseOrderLine line : orderLines) {
      idx++;
      line.setPurchaseOrder(parentOrder);
      BigDecimal price = line.getInTaxPrice();
      BigDecimal qty = line.getQty();
      lineService.fill(line, parentOrder);
      if (taxLines.get(idx) != null) {
        line.setTaxLine(taxLines.get(idx));
      }
      line.setQty(qty);
      line.setInTaxPrice(price);
      line.setPrice(Beans.get(TaxService.class).convertUnitPrice(true, line.getTaxLine(), price));
      Beans.get(PurchaseOrderLineService.class).compute(line, parentOrder);
      line.setPurchaseOrder(null);
    }
    return orderLines;
  }

  private TaxLine getTaxLine(String taxValue) {
    if (StringUtils.isEmpty(taxValue)) {
      return null;
    }
    Matcher m = Pattern.compile("(\\d+)%").matcher(taxValue);
    if (m.find()) {
      BigDecimal numTaxValue = new BigDecimal(m.group(1));
      return Query.of(TaxLine.class).filter("value = ?", numTaxValue).fetchOne();
    }
    return null;
  }

  private List<PurchaseOrderLine> appendProductInfo(List<PurchaseOrderLine> lines) {
    Set<String> codes = Lambda.set(lines, x -> x.getProductCode());
    List<PurchaseOrderLine> effectiveLines = new ArrayList<>();
    List<String> notExistCodes = new ArrayList<>();
    if (CollectionUtils.isNotEmpty(codes)) {
      List<Product> products = Query.of(Product.class).filter("code in (?)", codes).fetch(-1);
      Map<String, Product> dict = Lambda.map(products, k -> k.getCode());

      for (PurchaseOrderLine line : lines) {
        Product product = dict.get(line.getProductCode());
        if (product == null) {
          notExistCodes.add(line.getProductCode());
          continue;
        }
        line.setProduct(product);
        line.setUnit(product.getUnit());
        line.setProductName(product.getName());
        line.setDescription(product.getDescription());
        effectiveLines.add(line);
      }
    }
    logger.info("导入数据{}行，有效数据{}行，未找到商品信信编码：{}", lines.size(), effectiveLines.size(), notExistCodes);
    return effectiveLines;
  }
}
